---
title: Scroll Area
description: Using the scroll area machine in your project.
package: "@zag-js/scroll-area"
---

A scroll area provides a scrollable viewport with customizable scrollbars for
content that exceeds the container's dimensions.

<Resources pkg="@zag-js/scroll-area" />

<Showcase id="ScrollArea" />

**Features**

- Custom scrollbar styling and behavior
- Smooth scrolling with easing functions
- Touch and keyboard navigation support
- Automatic scrollbar hiding when not needed
- Nested scroll area support
- Programmatic scrolling to edges or coordinates

## Installation

To use the scroll area machine in your project, run the following command in
your command line:

<CodeSnippet id="scroll-area/installation.mdx" />

## Anatomy

To set up the scroll area correctly, you'll need to understand its anatomy and
how we name its parts.

> Each part includes a `data-part` attribute to help identify them in the DOM.

<Anatomy id="scroll-area" />

## Required style

It's important to note that the scroll area requires the following styles to be
applied to the viewport element to hide the scrollbar:

```css
[data-scope="scroll-area"][data-part="viewport"] {
  /* hide scrollbar */
  scrollbar-width: none;
  &::-webkit-scrollbar {
    display: none;
  }
}
```

## Usage

First, import the scroll area package into your project

```jsx
import * as scrollArea from "@zag-js/scroll-area"
```

The scroll area package exports two key functions:

- `machine` — The state machine logic for the scroll area widget.
- `connect` — The function that translates the machine's state to JSX attributes
  and event handlers.

> You'll also need to provide a unique `id` to the `useMachine` hook. This is
> used to ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the
scroll area machine in your project 🔥

<CodeSnippet id="scroll-area/usage.mdx" />

### Scrolling to edges

You can programmatically scroll to any edge of the scroll area using the
`scrollToEdge` method:

```jsx
// Scroll to bottom
api.scrollToEdge({ edge: "bottom" })

// Scroll to top with custom easing
api.scrollToEdge({
  edge: "top",
  duration: 500,
  easing: (t) => t * t,
})
```

### Scrolling to coordinates

Use the `scrollTo` method to scroll to specific coordinates:

```jsx
// Scroll to specific position
api.scrollTo({
  top: 100,
  left: 50,
})

// Scroll with smooth behavior
api.scrollTo({
  top: 200,
  behavior: "smooth",
  duration: 300,
})
```

### Checking scroll position

The API provides several properties to check the current scroll state:

```jsx
// Check if at edges
console.log(api.isAtTop) // boolean
console.log(api.isAtBottom) // boolean
console.log(api.isAtLeft) // boolean
console.log(api.isAtRight) // boolean

// Check for overflow
console.log(api.hasOverflowX) // boolean
console.log(api.hasOverflowY) // boolean

// Get scroll progress (0-1)
const progress = api.getScrollProgress() // { x: number, y: number }
```

### Conditional scrollbar rendering

Only render scrollbars when there's overflow content:

```jsx
{
  api.hasOverflowY && (
    <div {...api.getScrollbarProps({ orientation: "vertical" })}>
      <div {...api.getThumbProps({ orientation: "vertical" })} />
    </div>
  )
}

{
  api.hasOverflowX && (
    <div {...api.getScrollbarProps({ orientation: "horizontal" })}>
      <div {...api.getThumbProps({ orientation: "horizontal" })} />
    </div>
  )
}
```

### Scrollbar state

Get the current state of a scrollbar for styling purposes:

```jsx
const verticalState = api.getScrollbarState({ orientation: "vertical" })
// Returns: { hovering: boolean, scrolling: boolean, hidden: boolean }
```

### Nested scroll areas

Scroll areas can be nested within each other for complex layouts:

```jsx
<div {...api.getRootProps()}>
  <div {...api.getViewportProps()}>
    <div {...api.getContentProps()}>
      {/* Nested scroll area */}
      <ScrollAreaComponent style={{ maxHeight: 200 }}>
        {/* Inner content */}
      </ScrollAreaComponent>
    </div>
  </div>
</div>
```

## Styling guide

Earlier, we mentioned that each scroll area part has a `data-part` attribute
added to them to select and style them in the DOM.

### Scrolling state

When the user is actively scrolling, a `data-scrolling` attribute is set on the
scrollbar elements:

```css
[data-part="scrollbar"][data-scrolling] {
  /* styles when actively scrolling */
}

[data-part="thumb"][data-scrolling] {
  /* styles for thumb when scrolling */
}
```

### Hover state

When hovering over the scroll area or scrollbar, a `data-hover` attribute is
applied:

```css
[data-part="root"][data-hover] {
  /* styles when hovering over scroll area */
}

[data-part="scrollbar"][data-hover] {
  /* styles when hovering over scrollbar */
}
```

### Hidden state

Scrollbars can be automatically hidden when not needed:

```css
[data-part="scrollbar"][data-hidden] {
  /* styles for hidden scrollbar */
  opacity: 0;
  pointer-events: none;
}
```

### Orientation

Different styles can be applied based on scrollbar orientation:

```css
[data-part="scrollbar"][data-orientation="vertical"] {
  /* vertical scrollbar styles */
}

[data-part="scrollbar"][data-orientation="horizontal"] {
  /* horizontal scrollbar styles */
}
```

## Methods and Properties

The scroll area's `api` exposes the following methods and properties:

### Machine Context

The scroll area machine exposes the following context properties:

<ContextTable name="scroll-area" />

### Machine API

The scroll area `api` exposes the following methods:

<ApiTable name="scroll-area" />

### Data Attributes

<DataAttrTable name="scroll-area" />

### CSS Variables

<CssVarTable name="scroll-area" />
